Skip to content

Add ADR for GitHub Actions support - #98

Merged
jwbron merged 3 commits into
mainfrom
egg/github-actions-support
Feb 5, 2026
Merged

Add ADR for GitHub Actions support#98
jwbron merged 3 commits into
mainfrom
egg/github-actions-support

Conversation

@james-in-a-box

@james-in-a-box james-in-a-box Bot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Add design proposal for running egg in GitHub Actions

This ADR proposes a composite GitHub Action that orchestrates the full
egg stack (gateway + sandbox) within a GHA runner, mounting the
actions/checkout'd repo as the working repository.

The design preserves egg's security model (credential isolation via
gateway, policy enforcement, .git shadowing) while adapting to the
GHA environment. Users would reference the action with a prompt,
Anthropic API key, and GitHub token as inputs.

Key decisions:

  • Full gateway stack (not sandbox-only) to maintain credential isolation
  • Shell entrypoint (not docker-compose) for lifecycle control
  • Build from source in Phase 1, pre-built GHCR images in Phase 2
  • Dynamic config generation since there's no host setup in GHA

Three implementation phases: MVP core action, optimization with
pre-built images, and advanced features (private mode, multi-repo,
trigger templates).

Closes #78

Test plan:

  • Review the ADR for completeness and feasibility
  • Validate that the proposed architecture is compatible with GHA runner constraints (7GB RAM, 2 vCPU, Docker available)
  • Check that the gateway token handling path (GITHUB_USER_TOKEN) works for GHA tokens

Authored-by: egg

| Input | Required | Default | Description |
|-------|----------|---------|-------------|
| `prompt` | Yes | — | Task/prompt to pass to Claude Code |
| `anthropic-api-key` | Yes | — | Anthropic API key |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than an api key, let's use an oauth token

| `prompt` | Yes | — | Task/prompt to pass to Claude Code |
| `anthropic-api-key` | Yes | — | Anthropic API key |
| `github-token` | Yes | — | GitHub token for git operations |
| `mode` | No | `public` | Network mode: `public` or `private` |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's default to private for private repos

| `github-token` | Yes | — | GitHub token for git operations |
| `mode` | No | `public` | Network mode: `public` or `private` |
| `timeout` | No | `30` | Timeout in minutes |
| `model` | No | `sonnet` | Claude model to use |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's default to opus


## Open Questions

1. **Issue/PR-triggered prompts:** Should the action support commenting `/egg fix this` on an issue to trigger a run with issue context as the prompt? This would require a separate workflow template.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that will be addressed here #82

## Open Questions

1. **Issue/PR-triggered prompts:** Should the action support commenting `/egg fix this` on an issue to trigger a run with issue context as the prompt? This would require a separate workflow template.
2. **Image registry:** GHCR (free for public repos, integrated with GitHub) vs Docker Hub?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, let's go with ghcr

1. **Issue/PR-triggered prompts:** Should the action support commenting `/egg fix this` on an issue to trigger a run with issue context as the prompt? This would require a separate workflow template.
2. **Image registry:** GHCR (free for public repos, integrated with GitHub) vs Docker Hub?
3. **Branch strategy in GHA:** Should the action always create new branches from the checked-out ref, or should it support pushing to the current branch?
4. **Rate limiting:** Should the action enforce any rate limits on Claude API usage to prevent runaway costs?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet


1. **Issue/PR-triggered prompts:** Should the action support commenting `/egg fix this` on an issue to trigger a run with issue context as the prompt? This would require a separate workflow template.
2. **Image registry:** GHCR (free for public repos, integrated with GitHub) vs Docker Hub?
3. **Branch strategy in GHA:** Should the action always create new branches from the checked-out ref, or should it support pushing to the current branch?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should support both. We're building a fully autonomous agent here, let's keep the lockdowns as they are.

timeout: 30
```

### Action Inputs

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make the bot account configurable and support passing in the bot credentials as well. This should support the same setup as egg on a dev machine.

@jwbron

jwbron commented Feb 5, 2026

Copy link
Copy Markdown
Owner

Worth noting, we're going to support this being triggered as an "ai linter" as well per #77. That'll be handled after this is implemented.

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ADR Review: GitHub Actions Support

Solid design proposal that correctly preserves egg's security model. The phased approach is sensible. Several technical concerns to address before accepting.

Issues

1. Entrypoint flow describes a non-existent API sequence (Steps 6-7)

The ADR describes separate steps: "Create session + worktrees" (step 6) then "Start sandbox" (step 7). The actual gateway API uses POST /api/v1/session/create which atomically creates the session, allocates worktrees, and binds to a container IP. The launcher in sandbox/egg_lib/runtime.py calls _allocate_container_ip() first, then create_session() which does worktree creation internally. The ADR should reflect this actual flow or explain how it will differ for GHA.

2. Generated repositories.yaml is incomplete

The proposed config only has local_repos.paths and github_username, but the actual config format (per config/repositories.yaml.example) requires writable_repos, bot_username, user_mode block (with github_user, git_name, git_email), and repo_settings with auth_mode. The gateway's repo_parser.py will likely fail or behave unexpectedly with this minimal config. The ADR should specify the full generated config or explain what gateway changes are needed to accept a minimal config.

3. Anthropic API key routing is unclear

The sandbox sets ANTHROPIC_BASE_URL=http://egg-gateway:9848 and the gateway proxies API calls, injecting credentials. The ADR lists anthropic-api-key as an action input passed to the sandbox, but the current architecture has the gateway handle API key injection. The ADR should clarify whether the key goes to the gateway (matching current arch) or directly to the sandbox (diverging from it).

4. Build-from-source Phase 1 may be impractical

Building two Docker images from source on every GHA run is likely to take 5-15 minutes, especially the sandbox image which installs Python packages, Node.js, Claude Code, and numerous dev tools. Consider whether Phase 1 should use GHCR images from the start, or at minimum acknowledge the expected build time and suggest caching strategies.

5. Resource constraints need concrete analysis

The ADR notes "7GB RAM, 2 vCPU may constrain Claude Code" under consequences but doesn't analyze whether this is actually viable. The gateway runs Flask + Squid proxy, the sandbox runs Claude Code (Node.js) — what's the expected memory footprint? If it won't fit in 7GB, the ADR should say so and propose alternatives (larger runners, dropping Squid in GHA mode).

6. $GITHUB_WORKSPACE path mapping needs detail

The gateway's worktree manager creates worktrees at ~/.egg-worktrees/{container_id}/{repo_name} from the source repo's .git. In GHA, the .git is at $GITHUB_WORKSPACE/.git. The ADR should be explicit about how the workspace path maps through the gateway's worktree creation — specifically, the gateway needs the .git directory mounted at a path it knows about.

Minor

  • Ensure 172.32.0.0/24 doesn't collide with the runner's own Docker networks.
  • Open Question 2 (GHCR vs Docker Hub): GHCR is the obvious choice given the GitHub-native context — doesn't feel like a real open question.
  • No mention of what happens if the GHA runner is killed mid-run (orphaned containers/networks).

What's good

  • Correct decision to keep the full gateway stack for credential isolation.
  • Shell entrypoint over docker-compose is the right call for Phase 1.
  • Alternatives considered section is thorough with well-reasoned rejections.
  • Phased approach with clear deliverables and success criteria.

Recommendation

Address #1 (API flow accuracy), #2 (config completeness), and #3 (API key routing) before accepting — these would cause implementation friction. #4 (build time) is worth acknowledging explicitly even if deferred to Phase 2.

— Authored by egg

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing all review feedback:

@jwbron inline comments:

Re: OAuth token (line 69): Agreed. Changed anthropic-api-key to anthropic-oauth-token. The token is passed to the gateway as CLAUDE_CODE_OAUTH_TOKEN, matching the gateway's credential priority (OAuth > API key). The sandbox never sees it — all API calls route through the gateway's /v1/messages proxy.

Re: Default mode (line 71): Agreed. Changed default to auto, which queries GitHub API for repo visibility. Private/internal repos → private mode, public repos → public mode.

Re: Default model (line 73): Agreed. Changed to opus.

Re: Bot account (line 64): Agreed. Added bot-github-token and bot-username inputs. When bot-github-token is provided, it's passed to the gateway as BOT_GITHUB_TOKEN. The generated repositories.yaml now includes bot_username, repo_settings with auth_mode, and user_mode — matching the full config format expected by repo_parser.py.

Re: Open question 1 (line 224): Resolved — referenced #82 for trigger templates in Phase 3.

Re: Open question 2 (line 225): Resolved — GHCR.

Re: Open question 3 (line 226): Resolved — supports both new branches and current branch. Gateway lockdowns apply as-is.

Re: Open question 4 (line 227): Resolved — deferred.


@james-in-a-box review issues:

#1 (API flow accuracy): Fixed. Steps 6-7 replaced with a single step reflecting the actual POST /api/v1/sessions/create atomic flow — pre-allocate container IP, then one API call that queries visibility, filters repos, creates worktrees, and registers the session.

#2 (Config completeness): Fixed. Generated repositories.yaml now includes writable_repos, bot_username, repo_settings with auth_mode, user_mode block, and local_repos.paths. Added explicit workspace path mapping detail.

#3 (API key routing): Fixed (now OAuth token routing). Clarified that the token goes to the gateway as CLAUDE_CODE_OAUTH_TOKEN, the sandbox sets ANTHROPIC_BASE_URL=http://egg-gateway:9848, and the gateway's /v1/messages proxy injects credentials. Added a dedicated "Anthropic credentials" subsection under Gateway Token Handling.

#4 (Build time): Agreed — moved GHCR images to Phase 1. Building from source is impractical (5-15 min build times). Phase 1 now includes the release-images.yml workflow as a deliverable.

#5 (Resource constraints): Added a concrete Resource Analysis section with estimated memory footprint table (~850 MB - 1.15 GB baseline, leaving ~5.5-6 GB for Claude Code). Noted Squid could be dropped if tight, and larger runners as a recommendation.

#6 (Workspace path mapping): Added explicit detail — $GITHUB_WORKSPACE/.git bind-mounted into gateway at /repos/{repo-name}/.git, worktrees created at ~/.egg-worktrees/{container_id}/{repo_name}, path returned by session API and mounted into sandbox.

Minor items:

  • Network collision: Changed to dynamically allocated subnet (inspects existing Docker networks).
  • GHCR: Resolved per owner feedback.
  • Orphaned containers: Added trap EXIT handler note and clarified that hard-killed runner VMs are recycled by GHA.

— Authored by egg

james-in-a-box Bot pushed a commit that referenced this pull request Feb 5, 2026
Detailed technical plan for Phase 1 implementation of the GitHub
Actions ADR (#98). Covers all deliverables (action.yml, entrypoint.sh,
config generation, GHCR image publishing, integration tests), maps
each step to existing codebase references, and identifies risks and
open items.

Closes #78 (partially — plan only, implementation to follow)
Keep GitHub Actions Support entry, drop removed Egg Repository
Onboarding entry that no longer exists on main.
@jwbron
jwbron merged commit a2d8e8a into main Feb 5, 2026
4 checks passed
james-in-a-box Bot pushed a commit that referenced this pull request Feb 5, 2026
Detailed technical plan for Phase 1 implementation of the GitHub
Actions ADR (#98). Covers all deliverables (action.yml, entrypoint.sh,
config generation, GHCR image publishing, integration tests), maps
each step to existing codebase references, and identifies risks and
open items.

Closes #78 (partially — plan only, implementation to follow)
jwbron pushed a commit that referenced this pull request Feb 5, 2026
* Add implementation plan for GitHub Actions support

Detailed technical plan for Phase 1 implementation of the GitHub
Actions ADR (#98). Covers all deliverables (action.yml, entrypoint.sh,
config generation, GHCR image publishing, integration tests), maps
each step to existing codebase references, and identifies risks and
open items.

Closes #78 (partially — plan only, implementation to follow)

* Address review feedback on GHA implementation plan

Correct repo_parser.py attribution to config/repo_config.py and
shared/egg_config/config.py, add ADR dependency caveat, document
.git shadow mount rationale, clarify dynamic subnet allocation for
GHA, scope .dockerignore to separate PR, improve timeout mechanism
to use docker stop, use github.event.repository.visibility context
variable for mode detection, and pin image tags in action.yml.

* Add ADR for GitHub Actions support (#98)

* Add ADR for GitHub Actions support (#78)

* Address PR #98 review feedback on GHA ADR

---------

Co-authored-by: egg <egg@example.com>

* Add implementation plan for GitHub Actions support

Detailed technical plan for Phase 1 implementation of the GitHub
Actions ADR (#98). Covers all deliverables (action.yml, entrypoint.sh,
config generation, GHCR image publishing, integration tests), maps
each step to existing codebase references, and identifies risks and
open items.

Closes #78 (partially — plan only, implementation to follow)

* Address review feedback on GHA implementation plan

Correct repo_parser.py attribution to config/repo_config.py and
shared/egg_config/config.py, add ADR dependency caveat, document
.git shadow mount rationale, clarify dynamic subnet allocation for
GHA, scope .dockerignore to separate PR, improve timeout mechanism
to use docker stop, use github.event.repository.visibility context
variable for mode detection, and pin image tags in action.yml.

* Implement GitHub Actions support (Phase 1 MVP)

Add composite GitHub Action that orchestrates the full egg stack (gateway
+ sandbox) within a GHA runner. This enables running egg in CI/CD
pipelines while maintaining the same security model as local execution.

Deliverables:
- action/action.yml: Composite action definition with inputs/outputs
- action/entrypoint.sh: Container orchestration (pull, network, gateway,
  session, sandbox lifecycle with cleanup trap)
- action/generate-config.sh: Ephemeral config generation for gateway
- .github/workflows/release-images.yml: GHCR image publishing on release
- .github/workflows/test-action.yml: Integration tests for the action
- gateway/Dockerfile: Fix EXPOSE ports (9847->9848, 3128->3129)

Issue: #78

* Address review feedback on Phase 1 implementation

- Fix proxy var leak in exec mode: don't pass HTTP_PROXY/HTTPS_PROXY to
  sandbox container since run_exec() doesn't strip them before exec'ing
  Claude Code. Network isolation maintained via DNS and network topology.
- Remove session response echo that leaked full session token to CI logs.
  The redacted token (first 8 chars) is still printed.
- Replace bc-based health check timing with bash SECONDS builtin for
  portability across self-hosted runners.
- Add Squid proxy health check for private mode — verifies proxy is
  accepting connections before starting sandbox.
- Remove redundant GITHUB_USER_TOKEN from secrets.env — gateway reads it
  from the environment variable, not from this file.
- Add EGG_QUIET=1 to sandbox container to suppress startup banner noise
  in CI logs.
- Use associative array in allocate_subnet for O(1) subnet lookups
  instead of repeated grep.
- Update test-action.yml assertion for secrets.env contents.

* Fix CI failures in test-action workflow

- Use $GITHUB_RUN_ID instead of hardcoded values (99999/88888) — GHA
  built-in env vars cannot be overridden by step-level env blocks
- Replace `! grep` with if/then/exit pattern to avoid SC2251 (errexit
  skip under negated command)

* Fix config generation test for GHA built-in env vars

GITHUB_REPOSITORY, GITHUB_ACTOR, and GITHUB_ACTOR_ID are also built-in
GHA variables that cannot be overridden by step-level env blocks.
Validate against the actual runtime values instead of hardcoded test
values. Clean up config dir between test steps since both now use the
same GITHUB_RUN_ID.

* Fix grep regex issue with bot actor names

GITHUB_ACTOR can be "app[bot]" where [bot] is interpreted as a regex
character class. Use grep -F for fixed string matching in all config
generation test assertions.

* Move GHA ADR from not-implemented to in-progress

Phase 1 implementation is underway in PR #111. Update ADR status from
"Proposed" to "In Progress", move the file to docs/adr/in-progress/,
and fix references in the ADR index and implementation plan.

---------

Co-authored-by: egg <egg@example.com>
Co-authored-by: james-in-a-box[bot] <246424927+james-in-a-box[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Run egg in github actions

1 participant